package cn.xinfei.xdecision.data.core.context;

import cn.xinfei.xdecision.common.model.datax.consts.VariableConst;
import cn.xinfei.xdecision.common.service.rpc.RequestContextConstant;
import cn.xinfei.xdecision.data.core.trace.VarRequestWrapper;
import cn.xinfei.xdecision.model.BaseVarRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;

@Component
@Slf4j
@ConditionalOnProperty(name = "xdecision.data.context.enabled", matchIfMissing = true)
public class VarContextFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        VarRequestWrapper varRequestWrapper = new VarRequestWrapper(request);
        String requestData = varRequestWrapper.getRequestData();
        if (Objects.nonNull(requestData) && StringUtils.hasText(requestData)) {
            BaseVarRequest varRequest = JSON.parseObject(requestData, BaseVarRequest.class);
            JSONObject inputParamJson = varRequest.inputParams();
            String requestId = varRequest.requestId();

            DefaultContext varContext = new DefaultContext();
            if (StringUtils.hasText(requestId)) {
                ContextHolder.setCurrentContext(varContext.add(VariableConst.REQUEST_ID, requestId));
                MDC.put(VariableConst.REQUEST_ID, requestId);
            }
            String traceId;
            if (org.apache.commons.lang3.StringUtils.isBlank(MDC.get(VariableConst.TRACE_ID))) {
                traceId = UUID.randomUUID().toString().trim().replaceAll("-", "");
                MDC.put(VariableConst.TRACE_ID, traceId);
            } else {
                traceId = MDC.get(VariableConst.TRACE_ID);
            }

            if (inputParamJson != null && !inputParamJson.isEmpty()) {
                ContextHolder.clearCurrentContext();
                ContextHolder.setCurrentContext(varContext
                        .add(RequestContextConstant.APP, inputParamJson.getOrDefault(RequestContextConstant.APP, ""))
                        .add(RequestContextConstant.APP_NAME, inputParamJson.getOrDefault(RequestContextConstant.APP_NAME, ""))
                        .add(RequestContextConstant.APP_VERSION, inputParamJson.getOrDefault(RequestContextConstant.APP_VERSION, ""))
                        .add(RequestContextConstant.BIZ_FLOW_NUMBER, inputParamJson.getOrDefault(RequestContextConstant.BIZ_FLOW_NUMBER, requestId))
                        .add(RequestContextConstant.BIZ_TYPE, inputParamJson.getOrDefault(RequestContextConstant.BIZ_TYPE, ""))
                        .add(RequestContextConstant.COLUMN_REQUESTER, RequestContextConstant.SYSTEM)
                        .add(RequestContextConstant.DEVICE_ID, inputParamJson.getOrDefault(RequestContextConstant.DEVICE_ID, ""))
                        .add(RequestContextConstant.ID_CARD_NUMBER, inputParamJson.getOrDefault(RequestContextConstant.ID_CARD_NUMBER, ""))
                        .add(RequestContextConstant.INNER_APP, inputParamJson.getOrDefault(RequestContextConstant.INNER_APP, ""))
                        .add(RequestContextConstant.MOBILE, inputParamJson.getOrDefault(RequestContextConstant.MOBILE, ""))
                        .add(RequestContextConstant.PRODUCT_TYPE, inputParamJson.getOrDefault(RequestContextConstant.PRODUCT_TYPE, ""))
                        .add(RequestContextConstant.REPORT_ID, inputParamJson.getOrDefault(RequestContextConstant.REPORT_ID, requestId))
                        .add(RequestContextConstant.SEQ_ID, traceId)
                        .add(RequestContextConstant.SOURCE_TYPE, inputParamJson.getOrDefault(RequestContextConstant.SOURCE_TYPE, ""))
                        .add(RequestContextConstant.USER_ID, inputParamJson.getOrDefault(RequestContextConstant.USER_ID, ""))
                );
            }

            log.info("requestId ={} traceId = {} requestUrl = {} method = {},context = {} ",
                    requestId,
                    traceId,
                    request.getRequestURI(),
                    request.getMethod(),
                    JSONObject.toJSONString(ContextHolder.getCurrentContext()));
        }
        filterChain.doFilter(varRequestWrapper, response);
    }

    @Override
    public void destroy() {
        ContextHolder.clearCurrentContext();
        MDC.clear();
    }
}